/**
 * 
 */
package com.deck.server.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.xpath.XPathAPI;
import org.apache.xpath.objects.XObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.deck.server.shared.domain.Card;
import com.deck.server.shared.domain.Deck;
import com.deck.server.shared.domain.DeckInfo;

/**
 * @author Vincentas
 *
 */
public class QuizletDeckImporter implements DeckImporter {

	/* (non-Javadoc)
	 * @see com.deck.server.server.DeckImporter#importDeck(java.net.URL)
	 */
	@Override
	public Deck importDeck(URL deckUrl) throws DeckImportException {
		Pattern pattern = Pattern.compile("http://quizlet.com/(\\d+).*");
		
		Matcher matcher = pattern.matcher(deckUrl.toString());
		
		String deckId;
		if (matcher.matches()) {
			deckId = matcher.group(1);
		} else {
			throw new DeckImportException("Import from provided URL (" + deckUrl + ") is not possible at this time");
		}
		
		String deckAddress = "http://quizlet.com/" + deckId;
				
		try {
			DeckInfo deckInfo = readDeckInfo(new URL(deckAddress));
			Set<Card> cards = readCards(new URL(deckAddress + "/export"));		
			Deck deck = new Deck();
			
			deckInfo.setId(deckId);
			deckInfo.setCardCount(cards.size());
			
			deck.setCards(cards);
			deck.setDeckInfo(deckInfo);
		} catch (Throwable throwable) {
			throwable.printStackTrace();
		}
		
		return null;
	}
	
	private Document getDocument(URL url) throws IOException, SAXException, ParserConfigurationException {
		return getDocument(url.openStream());
	}
	
	private Document getDocument(InputStream is) throws IOException, SAXException, ParserConfigurationException {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
	
		DocumentBuilder documentBuilder = factory.newDocumentBuilder();
		Document document = documentBuilder.parse(is);
		
		return document;
	}
	
	private DeckInfo readDeckInfo(URL deckInfoURL) throws IOException, SAXException, ParserConfigurationException, XPathExpressionException {
		Document document = getDocument(deckInfoURL);
		
		DeckInfo result = new DeckInfo();
		
		Set<String> tags = new HashSet<String>();		
		try {
			NodeList nodeList = XPathAPI.selectNodeList(document, "//em/a");
			for (int i = 0, n = nodeList.getLength(); i < n; i++) {
				Node node = nodeList.item(i);
				tags.add(node.getTextContent());
			}		
			
			Node node = XPathAPI.selectSingleNode(document, "//div/h2");
			result.setName(node.getTextContent());

		} catch (TransformerException e) {
			e.printStackTrace();
		}
		
		{
			XPath xPath = XPathFactory.newInstance().newXPath();
			XPathExpression xPathExpression = xPath.compile("//div[@style='margin: 10px 0px 5px 0px; line-height: 150%;']/div[@style='display: none']/p");
			int i = 10;
			
			String description = xPathExpression.evaluate(document);		
			result.setDescription(description);
		}

		
		return result;
	}
	
	
	
	private Set<Card> readCards(URL cardsURL) throws XPathExpressionException, IOException, SAXException, ParserConfigurationException {
		Set<Card> result = new HashSet<Card>();
		
		XPath xPath = XPathFactory.newInstance().newXPath();
		XPathExpression xPathExpression = xPath.compile("//textarea");
		
		String text = xPathExpression.evaluate(getDocument(cardsURL));		
		List<String> readLines = IOUtils.readLines(new StringReader(text));
				
		int id = 0;
		for (String line : readLines) {
			String[] parts = StringUtils.split(line, "\\t");
			
			Card card = new Card();
			card.setFront(parts[1]);
			card.setBack(parts[0]);
			card.setId(Integer.toString(id++));
			
			result.add(card);
		}
		
		return result;
	}
}
